/*
 * @(#)CMPPProtocolDecoder.java 1.0 2013-6-26
 *
 * Copyright (c) 2009 Sunyard System Engineering Co., Ltd. All rights reserved.
 *
 * This software is the confidential and proprietary information of Sunyard
 * System Engineering Co., Ltd. ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in accordance
 * with the terms of the license agreement you entered into with Sunyard.
 */
/*
 * Modification History: Date Author Version Description
 * ------------------------------------------------------------------
 *
 */

package vsmg.cmpp.codec;

import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import vsmg.cmpp.CMPPKey;
import vsmg.cmpp.entity.CMPPActiveTest;
import vsmg.cmpp.entity.CMPPActiveTestResp;
import vsmg.cmpp.entity.CMPPConnect;
import vsmg.cmpp.entity.CMPPConnectResp;
import vsmg.cmpp.entity.CMPPDeliverResp;
import vsmg.cmpp.entity.CMPPMsgHeader;
import vsmg.cmpp.entity.CMPPSubmit;
import vsmg.cmpp.entity.CMPPSubmitResp;
import vsmg.cmpp.entity.CMPPTerminate;
import vsmg.cmpp.entity.CMPPTerminateResp;

/**
 *
 *
 * @version 1.0 2013-6-26
 * @author xinx.wang@sunyard.com
 */
public class CMPPProtocolDecoder extends CumulativeProtocolDecoder {

	private static Logger	logger	= Logger.getLogger(CMPPProtocolDecoder.class);

	private final int		headLength;

	public CMPPProtocolDecoder(int headLength) {

		super();
		this.headLength = headLength;
	}

	/**
	 * @return true if and only if there's more to decode in the buffer and you
	 *         want to have doDecode method invoked again. Return false if
	 *         remaining data is not enough to decode, then this method will be
	 *         invoked again when more data is cumulated.
	 */
	@Override
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) {
		try {
			if (in.remaining() >= this.headLength) {
				in.mark();
				final int start = in.position();
				final int pkgLen = in.getInt();
				if (in.remaining() >= (pkgLen - 4)) {
					logger.debug("session[" + session.getId() + "] doDecode. " + in.getHexDump(pkgLen));

					int cmd = 0;
					CMPPMsgHeader pdu = new CMPPMsgHeader(in, pkgLen);
					cmd = pdu.getCommandId();
					switch (cmd) {
					case CMPPKey.COMMAND_CONNECT:
						pdu = new CMPPConnect(pdu, in);
						break;
					case CMPPKey.COMMAND_CONNECT_RESP:
						pdu = new CMPPConnectResp(pdu, in);
						break;
					case CMPPKey.COMMAND_DELIVER:
						break;
					case CMPPKey.COMMAND_DELIVER_RESP:
						pdu = new CMPPDeliverResp(pdu, Integer.parseInt((String) session.getAttribute("version")), in);
						break;
					case CMPPKey.COMMAND_SUBMIT:
						pdu = new CMPPSubmit(pdu, Integer.parseInt((String) session.getAttribute("version")), in);
						break;
					case CMPPKey.COMMAND_SUBMIT_RESP:
						pdu = new CMPPSubmitResp(pdu);
						break;
					case CMPPKey.COMMAND_TERMINATE:
						pdu = new CMPPTerminate(pdu);
						break;
					case CMPPKey.COMMAND_TERMINATE_RESP:
						pdu = new CMPPTerminateResp(pdu);
						break;
					case CMPPKey.COMMAND_ACTIVE_TEST:
						pdu = new CMPPActiveTest(pdu);
						break;
					case CMPPKey.COMMAND_ACTIVE_TEST_RESP:
						pdu = new CMPPActiveTestResp(pdu, in);
						break;
					default:
						break;
					}
					out.write(pdu);
					in.position(start + pkgLen);

					if (in.remaining() >= this.headLength) {
						return true;
					}
				} else {
					in.reset();
				}
			}
		} catch (final Exception e) {
			logger.error(e, e);
			session.closeNow();
		}
		return false;
	}

}
